package sinalgo.tools;

public class MathUtils {

	private static final double A1 = -39.6968302866538;
	private static final double A2 = 220.946098424521; 
	private static final double A3 = -275.928510446969; 
	private static final double A4 = 138.357751867269; 
	private static final double A5 = -30.6647980661472; 
	private static final double A6 = 2.50662827745924; 
	private static final double B1 = -54.4760987982241; 
	private static final double B2 = 161.585836858041; 
	private static final double B3 = -155.698979859887; 
	private static final double B4 = 66.8013118877197; 
	private static final double B5 = -13.2806815528857;
	private static final double C1 = -7.78489400243029E-03;
	private static final double C2 = -0.322396458041136;
	private static final double C3 = -2.40075827716184;
	private static final double C4 = -2.54973253934373;
	private static final double C5 = 4.37466414146497;
	private static final double C6 = 2.93816398269878;
	private static final double D1 = 7.78469570904146E-03;
	private static final double D2 = 0.32246712907004;
	private static final double D3 = 2.445134137143;
	private static final double D4 = 3.75440866190742;
	private static final double P_LOW = 0.02425;
	private static final double P_HIGH = 1 - P_LOW;	

	public static double average( double[] sample ) {
		int n = sample.length;
		double s = 0;
		for( int x=0; x<n; x++) s += sample[x];
		return s/n;
	}
	
	public static double stdev( double[] sample ) {
		int n = sample.length;
		double avg = average(sample);
		double s = 0;
		for( int x=0; x<n; x++ ) s += Math.pow( sample[x] - avg, 2 );
		s /= n-1;
		return Math.sqrt( s );
	}
	
	public static double normSInv( double p ) throws RuntimeException {
	   double q, r;
	   if (p < 0 || p > 1) { 
	  	 throw new RuntimeException("Invalid Argument!");
	   } else if ( p < P_LOW ) {
	      q = Math.sqrt(-2 * Math.log(p));
	      return (((((C1 * q + C2) * q + C3) * q + C4) * q + C5) * q + C6) / ((((D1 * q + D2) * q + D3) * q + D4) * q + 1);
	   } else if ( p <= P_HIGH ) {
	      q = p - 0.5;
	      r = q * q;
	      return (((((A1 * r + A2) * r + A3) * r + A4) * r + A5) * r + A6) * q / (((((B1 * r + B2) * r + B3) * r + B4) * r + B5) * r + 1);
	   } else {
	      q = Math.sqrt((-2 * Math.log(1 - p)));
	      return -(((((C1 * q + C2) * q + C3) * q + C4) * q + C5) * q + C6) / ((((D1 * q + D2) * q + D3) * q + D4) * q + 1);
	   }
	}
	
	public static double confidence( double alpha, double stdev, int size ) {
		double z = normSInv( 1 - alpha/2 );
		return ( z * stdev / Math.sqrt(size) );
	}
	
	public static double confidence( double alpha, double[] sample ) {
		double z = normSInv( 1 - alpha/2 );
		double stdev = stdev(sample);
		int size = sample.length;
		return ( z * stdev / Math.sqrt(size) );
	}	
	
	/*
	 * O operador mod (%) do java não funciona de forma adequada em alguns casos (para números
	 * negativos, por exemplo). Esta função é uma adaptação desse operador para corrigir tal
	 * problema.
	 * */
	public static double modulus( double a, double b ) {
			return (a % b + b) % b;
	}
	
	
}
